//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package roadmap_state_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/roadmap_dao"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/roadmap_content_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/roadmap_state_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *RoadmapStateApiImpl) SetState(ctx context.Context, req *roadmap_state_api.SetStateRequest) (*roadmap_state_api.SetStateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_state_api.SetStateResponse{
			Code:   roadmap_state_api.SetStateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_state_api.SetStateResponse{
			Code:   roadmap_state_api.SetStateResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
		}, nil
	}
	if !(roadmapItem.OwnerUserId == sessionItem.UserId || roadmapItem.PubState) {
		return &roadmap_state_api.SetStateResponse{
			Code:   roadmap_state_api.SetStateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	nodeItem, err := roadmap_dao.NodeDao.Get(ctx, req.RoadmapId, req.NodeId)
	if err != nil {
		return &roadmap_state_api.SetStateResponse{
			Code:   roadmap_state_api.SetStateResponse_CODE_NO_NODE,
			ErrMsg: "节点不存在",
		}, nil
	}
	dataOk := false
	if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_TOPIC) || nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_SUB_TOPIC) {
		_, dataOk = req.BasicInfo.StateData.(*roadmap_state_api.BasicStateInfo_TopicState)
	} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_TODO_LIST) {
		_, dataOk = req.BasicInfo.StateData.(*roadmap_state_api.BasicStateInfo_TodoListState)
	}
	if !dataOk {
		return &roadmap_state_api.SetStateResponse{
			Code:   roadmap_state_api.SetStateResponse_CODE_WRONG_DATA,
			ErrMsg: "错误的数据类型",
		}, nil
	}

	opId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		dbItem := &roadmap_dao.StateInfoDbItem{
			RoadmapId: req.RoadmapId,
			NodeId:    req.NodeId,
			UserId:    sessionItem.UserId,
			TimeStamp: nowTime,
			BasicInfo: roadmap_dao.BasicStateInfoDbItem{},
		}
		opDbItem := &roadmap_dao.StateOpItemDbItem{
			OpId:         opId,
			RoadmapId:    req.RoadmapId,
			RoadmapTitle: roadmapItem.BasicInfo.Title,
			NodeId:       req.NodeId,
			OpType:       uint32(roadmap_state_api.STATE_OP_TYPE_STATE_OP_SET),
			TimeStamp:    nowTime,
			UserId:       sessionItem.UserId,
			StateData:    roadmap_dao.StateDataDbItem{},
		}
		if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_TOPIC) || nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_SUB_TOPIC) {
			stateData := req.BasicInfo.StateData.(*roadmap_state_api.BasicStateInfo_TopicState)
			dbItem.BasicInfo.TopicState = &roadmap_dao.NodeTopicStateDbItem{
				State: uint32(stateData.TopicState.State),
				Title: stateData.TopicState.Title,
			}
			opDbItem.StateData.TopicState = dbItem.BasicInfo.TopicState
		} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_TODO_LIST) {
			stateData := req.BasicInfo.StateData.(*roadmap_state_api.BasicStateInfo_TodoListState)
			doneList := []roadmap_dao.NodeTodoStateItemDbItem{}
			for _, srcItem := range stateData.TodoListState.DoneList {
				doneList = append(doneList, roadmap_dao.NodeTodoStateItemDbItem{
					TodoId: srcItem.TodoId,
					Title:  srcItem.Title,
				})
			}
			dbItem.BasicInfo.TodoListState = &roadmap_dao.NodeTodoListStateDbItem{
				DoneList: doneList,
			}
			opDbItem.StateData.TodoListState = dbItem.BasicInfo.TodoListState
		}

		err = roadmap_dao.StateDao.Upsert(sessCtx, dbItem)
		if err != nil {
			return nil, err
		}
		//增加日志
		err = roadmap_dao.StateOpDao.Insert(sessCtx, opDbItem)
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.NodeOpIndexDao.Insert(sessCtx, &roadmap_dao.NodeOpIndexDbItem{
			OpId:      opId,
			RoadmapId: req.RoadmapId,
			NodeId:    req.NodeId,
			TimeStamp: nowTime,
		})
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.UserOpIndexDao.Insert(sessCtx, &roadmap_dao.UserOpIndexDbItem{
			OpId:      opId,
			UserId:    sessionItem.UserId,
			TimeStamp: nowTime,
		})
		if err != nil {
			return nil, err
		}
		//增加热度值
		err = roadmap_dao.RoadmapInfoDao.IncHotValue(sessCtx, req.RoadmapId, 10)
		if err != nil {
			return nil, err
		}
		return &roadmap_state_api.SetStateResponse{
			Code: roadmap_state_api.SetStateResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_state_api.SetStateResponse), nil
}

func (apiImpl *RoadmapStateApiImpl) ListState(ctx context.Context, req *roadmap_state_api.ListStateRequest) (*roadmap_state_api.ListStateResponse, error) {
	emptyList := []*roadmap_state_api.StateInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_state_api.ListStateResponse{
			Code:      roadmap_state_api.ListStateResponse_CODE_WRONG_SESSION,
			ErrMsg:    "会话不存在",
			StateList: emptyList,
		}, nil
	}
	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_state_api.ListStateResponse{
			Code:   roadmap_state_api.ListStateResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
		}, nil
	}
	if !(roadmapItem.OwnerUserId == sessionItem.UserId || roadmapItem.PubState) {
		return &roadmap_state_api.ListStateResponse{
			Code:      roadmap_state_api.ListStateResponse_CODE_NO_PERMISSION,
			ErrMsg:    "没有权限",
			StateList: emptyList,
		}, nil
	}
	if req.FilterbyNodeId {
		exist, err := roadmap_dao.NodeDao.Exist(ctx, req.RoadmapId, req.NodeId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &roadmap_state_api.ListStateResponse{
				Code:      roadmap_state_api.ListStateResponse_CODE_NO_NODE,
				ErrMsg:    "节点不存在",
				StateList: emptyList,
			}, nil
		}
	}

	stateItemList, err := roadmap_dao.StateDao.List(ctx, req.RoadmapId, sessionItem.UserId, req.FilterbyNodeId, req.NodeId)
	if err != nil {
		return nil, err
	}
	stateList := []*roadmap_state_api.StateInfo{}
	for _, stateItem := range stateItemList {
		stateList = append(stateList, stateItem.ToStateInfo())
	}
	return &roadmap_state_api.ListStateResponse{
		Code:      roadmap_state_api.ListStateResponse_CODE_OK,
		StateList: stateList,
	}, nil
}

func (apiImpl *RoadmapStateApiImpl) RemoveState(ctx context.Context, req *roadmap_state_api.RemoveStateRequest) (*roadmap_state_api.RemoveStateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_state_api.RemoveStateResponse{
			Code:   roadmap_state_api.RemoveStateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_state_api.RemoveStateResponse{
			Code:   roadmap_state_api.RemoveStateResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
		}, nil
	}
	if !(roadmapItem.OwnerUserId == sessionItem.UserId || roadmapItem.PubState) {
		return &roadmap_state_api.RemoveStateResponse{
			Code:   roadmap_state_api.RemoveStateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	stateItem, err := roadmap_dao.StateDao.Get(ctx, req.RoadmapId, req.NodeId, sessionItem.UserId)
	if err != nil {
		return &roadmap_state_api.RemoveStateResponse{
			Code: roadmap_state_api.RemoveStateResponse_CODE_OK,
		}, nil
	}

	opId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = roadmap_dao.StateDao.Remove(sessCtx, req.RoadmapId, req.NodeId, sessionItem.UserId)
		if err != nil {
			return nil, err
		}
		//写入操作日志
		err = roadmap_dao.StateOpDao.Insert(sessCtx, &roadmap_dao.StateOpItemDbItem{
			OpId:         opId,
			RoadmapId:    req.RoadmapId,
			RoadmapTitle: roadmapItem.BasicInfo.Title,
			NodeId:       req.NodeId,
			OpType:       uint32(roadmap_state_api.STATE_OP_TYPE_STATE_OP_REMOVE),
			TimeStamp:    nowTime,
			UserId:       sessionItem.UserId,
			StateData: roadmap_dao.StateDataDbItem{
				TopicState:    stateItem.BasicInfo.TopicState,
				TodoListState: stateItem.BasicInfo.TodoListState,
			},
		})
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.NodeOpIndexDao.Insert(sessCtx, &roadmap_dao.NodeOpIndexDbItem{
			OpId:      opId,
			RoadmapId: req.RoadmapId,
			NodeId:    req.NodeId,
			TimeStamp: nowTime,
		})
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.UserOpIndexDao.Insert(sessCtx, &roadmap_dao.UserOpIndexDbItem{
			OpId:      opId,
			UserId:    sessionItem.UserId,
			TimeStamp: nowTime,
		})
		if err != nil {
			return nil, err
		}
		return &roadmap_state_api.RemoveStateResponse{
			Code: roadmap_state_api.RemoveStateResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_state_api.RemoveStateResponse), nil
}
